package calao.client;

import java.util.Vector;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.ScrollPanel;

public class ServiceCallback
implements AsyncCallback
{

	static final Vector queue = new Vector();
	
	static int callCount = 0;

	public ServiceCallback() 
	{
		queue.add(this);
		callCount++;
	}

	public final void onFailure(Throwable caught) 
	{
		try {
			onThrow(caught);
		}
		catch (Throwable thrown) {
			Desktop desktop = Desktop.getDesktop();
			desktop.log(caught);
			if (hasNotConnectedCause(caught)) {
				desktop.showLoginPanel();
			}
			else {
				if (caught instanceof InvocationException) {
					desktop.showErrorBox(desktop.text.operationFailed(),
							desktop.text.serverUnreachable());			
				}
				else {
					ScrollPanel details = new ScrollPanel(new HTML(caught.toString()));
					details.setSize("100%", "150");
					desktop.showErrorBox(desktop.text.operationFailed(),
							desktop.text.serviceExceptionRaised(), details);
				}
			}
		}
		finally {
			completed();
		}
	}
	
	private static boolean hasNotConnectedCause(Throwable caught)
	{
		 if (caught instanceof NotConnectedException) return true;
		 if (caught.getCause()!=null) return hasNotConnectedCause(caught.getCause());
		 return false;
	}

	public final void onSuccess(Object result) 
	{ 
		try {
			onReturn(result);
		}
		finally {
			completed();
		}
	}

	void completed() 
	{
		queue.remove(this);
		callCount--;
		while ((!queue.isEmpty()) && queue.firstElement() instanceof Command) {
			((Command)queue.firstElement()).execute();
			queue.remove(0);
		}
	}

	protected void onReturn(Object result) { }
	
	protected void onThrow(Throwable caught) 
	throws Throwable 
	{ 
		throw caught;
	}

	/** Defers execution of a command after all current service calls have returned.
	 */
	public static void defer(Command command)
	{
		if (queue.isEmpty()) command.execute();
		else queue.add(command);
	}
	
	public static int getPendingCallCount()
	{
		return callCount;
	}

}
